/*
This is the chat room server
*/

#include "keg.h"

int main(int argc, char* argv[])
{
	fd_set rfd, c_rfd;/*file descriptor set and copy*/
	struct sockaddr_in serv_addr, client_addr;
	int sockfd, client_sockfd, len, maxFD, numClients;
	char buf[BUFSIZ];

	sockfd = socket(PF_INET, SOCK_STREAM, 0);
	maxFD = sockfd;

	memset(client_array, 0, sizeof(client_array));
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(PORT);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	FD_ZERO(&rfd);/*zero out the file descriptor array*/

	if(bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
	{
		printf("Why'd you go and disconnect the server before the clients? Now you went and gave yourself a bind error!\n");
		exit(1);
	}

	listen(sockfd, MAX_CLIENTS);

	FD_SET(sockfd, &rfd);
	FD_SET(0, &rfd);
	numClients = 0;

	while(1)/*run continuously*/
	{
		int i;
		c_rfd = rfd;/*save values*/

		select(maxFD+1, &c_rfd, NULL, NULL, NULL);/*see which clients are ready to read from*/
		if(FD_ISSET(0, &c_rfd)) {
			break;
		}
		if(FD_ISSET(sockfd, &c_rfd))
		{
			len = sizeof(client_addr);

			client_sockfd = accept(sockfd, (struct sockaddr*)&client_addr, (socklen_t *) &len);

			memset(buf, '\0', BUFSIZ);

			if(numClients >= MAX_CLIENTS) {
				/* Send msg server full and kick user */
				write(client_sockfd, "-- Server Full", sizeof("-- Server Full"));
				close(client_sockfd);
				continue;
			}

			FD_SET(client_sockfd, &rfd);
			
			for(i = 0; i < MAX_CLIENTS; i++)
			{
				if(client_array[i] == 0)
				{
					client_array[i] = malloc(sizeof(client_info));
					client_array[i]->name[0] = '\0';
					client_array[i]->getName = 1;
					client_array[i]->fd = client_sockfd;

					maxFD = MAX(client_sockfd, maxFD);
					numClients++;

					break;
				}
			}
			
		} /* Close check for accepting clients */

		/*something is waiting to be read*/

		for(i = 0; i < MAX_CLIENTS; i++)
		{		

			if(client_array[i] != 0 && client_array[i]->fd != sockfd)
			{
				if(FD_ISSET(client_array[i]->fd, &c_rfd))
				{
					int readAmount;
					char tempBuf[MAX_RW+1];

					readAmount = read(client_array[i]->fd, tempBuf, MAX_RW);
					memset(buf, '\0', sizeof(buf));

					if(readAmount == 0) {
						numClients--;
						FD_CLR(client_array[i]->fd, &rfd);
						/* Clean up user */
						sprintf(buf, "-- %s has left the chat\n", client_array[i]->name);
						free(client_array[i]);
						client_array[i] = 0;
						/* Shout it */
						shout(buf);
						continue;
					}

					/* First get user name. */
					if(client_array[i]->getName) {
						int j;
						read(client_sockfd, buf, MAX_CLIENT_NAME);
						/* Remove newline from name */
						for(j = strlen(buf)-4; j < strlen(buf); j++)
							if(buf[j] == '\n' || buf[j] == '\r')
								buf[j] = '\0';

						strcpy(client_array[i]->name, buf);
						client_array[i]->getName = 0;
						memset(buf, '\0', sizeof(buf));
						sprintf(buf, "-- %s has joined the conversation in #retral.\n", client_array[i]->name);
						shout(buf);

						printf("Clients: ");
						for(j = 0; j < MAX_CLIENTS; j++)
							if(client_array[j] != 0)
							printf("%s, ", client_array[j]->name);
						printf("\n");

						continue;
					}
					
					tempBuf[readAmount] = '\0';
					if(strlen(client_array[i]->msg) == 0) {
						strcat(client_array[i]->msg, client_array[i]->name);
						strcat(client_array[i]->msg, ": ");
					}
					strcat(client_array[i]->msg, tempBuf);
					if(tempBuf[strlen(tempBuf)-1] == '\n') {
						shout(client_array[i]->msg);
						client_array[i]->msg[0] = '\0';
					}
				}
			}
		}
	}

	kickClients();
	return 0;
}

void shout(char* msg) {
	int i, j;
	for(i = 0; i < MAX_CLIENTS; i++)
		if(client_array[i] != 0)
			for(j = 0; j < strlen(msg);) {
				write(client_array[i]->fd, msg+j, MAX_RW);
				fsync(client_array[i]->fd); /* FIXME: this causes warning of implicitness*/
				j += MAX_RW;
			}
}

void kickClients(void) {
	int i;
	for(i = 0; i < MAX_CLIENTS; i++)
		if(client_array[i] != 0)
			close(client_array[i]->fd);
}
